#pragma once

#ifndef SIMU_QOBJECT
#define SIMU_QOBJECT

#include <cassert>

enum QType
{
    QTYPE_NONE,
    QTYPE_QNULL,
    QTYPE_QNUM,
    QTYPE_QSTRING,
    QTYPE_QDICT,
    QTYPE_QLIST,
    QTYPE_QBOOL,
    QTYPE_MAX,
};
/* this struct must have no other members than base */
struct QObject {
    QType type;
    size_t refcnt;
};

/*
 * Preprocessor sorcery ahead: use a different identifier for the
 * local variable in each expansion, so we can nest macro calls
 * without shadowing variables.
 */
#define QOBJECT_INTERNAL(obj, _obj) ({                          \
    typeof(obj) _obj = (obj);                                   \
    _obj ? container_of(&_obj->base, QObject, base) : NULL;     \
})
#define QOBJECT(obj) QOBJECT_INTERNAL((obj), MAKE_IDENTFIER(_obj))

static inline void qobject_init(QObject* obj, QType type)
{
    assert(QTYPE_NONE < type&& type < QTYPE_MAX);
    obj->refcnt = 1;
    obj->type = type;
}

#endif // !SIMU_QOBJECT
